package org.jpropelleralt.reaction.impl;

import java.util.IdentityHashMap;
import java.util.Map;

import org.jpropelleralt.box.Box;
import org.jpropelleralt.change.Change;
import org.jpropelleralt.change.ChangeDefault;
import org.jpropelleralt.reaction.Reaction;

/**
 * Simple reaction operating on a set of
 * input {@link Box}es, but applying itself
 * to one or more target {@link Box}es that 
 * are NOT known until the {@link Reaction} is
 * actually applied. 
 */
public class ReactionTask implements Reaction {

	private final Runnable task;
	private final IdentityHashMap<Box, Change> fixedChanges;
	
	/**
	 * Create a {@link ReactionTask}
	 * @param task				A {@link Runnable} that makes the changes to target {@link Box}es
	 * @param inputs			The inputs - when these change, the task will be run. Must include
	 * 							ALL data required by the task to run.
	 */
	public ReactionTask(Runnable task, Box... inputs) {
		this.task = task;
		
		//We always make an unknown-target shallow change (shallow/deep is irrelevant though).
		fixedChanges = new IdentityHashMap<Box, Change>();
		fixedChanges.put(null, ChangeDefault.shallowInstance());
		
		//We react to changes in all inputs
		for (Box box : inputs) {
			box.features().addReaction(this);
		}
		
		//FIXME this shouldn't be necessary - when a new constraint is made,
		//it should be able to declare it WILL make a change, rather than having to make
		//it immediately
		//Start out up to date
		apply(true);
	}
	
	@Override
	public void apply(boolean propagate) {
		task.run();
	}
	@Override
	public boolean completeChanges(Map<Box, Change> changes) {
		//Nothing to do
		return false;
	}

	@Override
	public Map<Box, Change> react(Map<Box, Change> changes) {
		//We will always change unknown targets
		return fixedChanges;
	}

}
